using System;
using System.Reflection;
using System.Text.RegularExpressions;
using NUnit.Framework;
using ValidationFramework.Extensions;
using ValidationFramework.Reflection;
#if (!SILVERLIGHT && !WindowsCE)
using ValidationFramework.Web.ASP;
#endif

namespace ValidationFramework.Tests
{
    [TestFixture]
    public sealed class RegexRuleTest
    {

        const string expectedErrorMessage = "expectedErrorMessage";
        const string expectedRuleSet = "EXPECTEDRULESET";
        const string expectedRegularExpression = @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
        const RegexOptions expectedRegexOptions = RegexOptions.IgnorePatternWhitespace;
     
        
        [TestFixture]
        public class Construction
        {
            [Test]
            public void Simple1()
            {
                var rule = new RegexRule(expectedRegularExpression)
                           	{
								RegexOptions = expectedRegexOptions
                           	};
                Assert.AreEqual(expectedRegularExpression, rule.ValidationExpression);
                Assert.AreEqual(expectedRegexOptions, rule.RegexOptions);
            }

            [Test]
            public void Simple2()
            {
            	var rule = new RegexRule(expectedRegularExpression);
                Assert.AreEqual(expectedRegularExpression, rule.ValidationExpression);
                Assert.AreEqual(RegexOptions.None, rule.RegexOptions);
            }

            [Test]
            public void Simple3()
            {
            	var rule = new RegexRule(expectedRegularExpression);
                Assert.AreEqual(expectedRegularExpression, rule.ValidationExpression);
                Assert.IsNull(rule.ErrorMessage);
                Assert.AreEqual(RegexOptions.None, rule.RegexOptions);
                Assert.IsFalse(rule.UseErrorMessageProvider);
            }

            [Test]
            public void TestRegexRange()
            {
                const RegexOptions minExpectedRegexOptions = RegexOptions.None;
				var rule1 = new RegexRule(expectedRegularExpression)
				{
					RegexOptions = minExpectedRegexOptions
				};
                Assert.AreEqual(minExpectedRegexOptions, rule1.RegexOptions);

#if (SILVERLIGHT)
                const RegexOptions maxExpectedRegexOptions = RegexOptions.CultureInvariant |
                                                             RegexOptions.ECMAScript |
                                                             RegexOptions.ExplicitCapture |
                                                             RegexOptions.IgnoreCase |
                                                             RegexOptions.IgnorePatternWhitespace |
                                                             RegexOptions.Multiline |
                                                             RegexOptions.None |
                                                             RegexOptions.RightToLeft |
                                                             RegexOptions.Singleline;
#else

                const RegexOptions maxExpectedRegexOptions = RegexOptions.Compiled |
                                                             RegexOptions.CultureInvariant |
                                                             RegexOptions.ECMAScript |
                                                             RegexOptions.ExplicitCapture |
                                                             RegexOptions.IgnoreCase |
                                                             RegexOptions.IgnorePatternWhitespace |
                                                             RegexOptions.Multiline |
                                                             RegexOptions.None |
                                                             RegexOptions.RightToLeft |
                                                             RegexOptions.Singleline;
#endif
				var rule2 = new RegexRule(expectedRegularExpression)
				{
					RegexOptions = maxExpectedRegexOptions
				};
                Assert.AreEqual(maxExpectedRegexOptions, rule2.RegexOptions);

            }



            [Test]
            public void ExceptionInvalidRegexOptions()
            {
                Exception argException = null;
                try
                {
					var rule = new RegexRule("foo");
					rule.SetProperty("RegexOptions", -1);
                }
                catch (TargetInvocationException e)
                {
                    argException = e.InnerException;
                }
                Assert.IsNotNull(argException);
            }


            [Test]
            [ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: value")]
            public void ExceptionValidationExpressionNull3()
            {
            	new RegexRule(null);
            }


            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "String cannot be empty.\r\nParameter name: value")]
            public void ExceptionValidationExpressionEmpty3()
            {
            	new RegexRule(string.Empty);
            }


        }


        [TestFixture]
        public class IsEquivalent
        {

            [Test]
            public void Simple()
            {
				var rule1 = new RegexRule("regex")
				{
					RegexOptions = RegexOptions.None
				};
				var rule2 = new RegexRule("regex")
				{
					RegexOptions = RegexOptions.None
				};
                Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new RegexRule("regex")
				{
					RegexOptions = RegexOptions.None
				};
				rule2 = new RegexRule("regex2")
				{
					RegexOptions = RegexOptions.None
				};
                Assert.IsFalse(rule1.IsEquivalent(rule2));
            }
        }


        [TestFixture]
        public class RuleInterpretation
        {
            [Test]
            public void Simple()
            {
				var rule = new RegexRule(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")
				{
					RegexOptions = RegexOptions.None
				};
                Assert.IsNotNull(rule.RuleInterpretation);

            }
        }


        [TestFixture]
        public class Validate
        {
            [Test]
            public void Simple()
            {
				var rule = new RegexRule(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")
				{
					RegexOptions = RegexOptions.None
				};

                Assert.IsTrue(rule.Validate(null, null, null, null));
                Assert.IsTrue(rule.Validate(null, string.Empty, null, null));
                Assert.IsFalse(rule.Validate(null, "aaa", null, null));
                Assert.IsTrue(rule.Validate(null, "a@b.com", null, null));

            }
        }
        
#if (!WindowsCE && !SILVERLIGHT)

        [TestFixture]
        public class GetBaseValidator
        {

            [Test]
            public void DateTime()
            {
				var rule = new RegexRule(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")
				{
					RegexOptions = RegexOptions.None
				};

                var ruleContext = new RuleContext { Rule = rule};
                var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, null);
                Assert.IsNotNull(list);
                Assert.AreEqual(1, list.Count);
            }

        }
#endif

        [TestFixture]
        public class CheckTypes
        {

            [Test]
            public void Simple()
            {
				var rule = new RegexRule("sss")
				{
					RegexOptions = RegexOptions.None
				};
                rule.CheckType(new MockInfoDescriptor(typeof (string).TypeHandle, "foo"));
            }


            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Member 'foo' must be a 'System.String' to be used for the ValidationFramework.RegexRule. Actual Type 'System.Int32'.\r\nParameter name: value")]
            public void CheckTypesException()
            {
				var rule = new RegexRule("sss")
				{
					RegexOptions = RegexOptions.None
				};
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
            }
        }
    }
}